package com.practice.security.crypto;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.KeyGenerator;

public interface CryptoHelper {
	
	/**
	 * Encrypt text.
	 * 
	 * @param plaintext
	 * @return
	 * @throws BusinessException
	 */
	public abstract String encrypt(String plaintext) throws IOException;

	/**
	 * Decrypt text.
	 * 
	 * @param ciphertext
	 * @return
	 * @throws BusinessException
	 */
	public abstract String decrypt(String ciphertext) throws IOException;

	/**
	 * Generate <code>Key</code> by specifying algorithm. Key will be
	 * initialized with secure random.
	 * 
	 * @param algorithm
	 * @return
	 * @throws NoSuchAlgorithmException
	 *             if specified algorithm is not supported by
	 *             <code>KeyGenerator</code>.
	 */
	public default Key generateKey(String algorithm) throws NoSuchAlgorithmException {
		KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
		keyGenerator.init(new SecureRandom());
		return keyGenerator.generateKey();
	}

	/**
	 * Write key to stream.
	 * 
	 * @param key
	 * @param output
	 * @throws IOException
	 */
	public default void writeKeyToStream(Key key, OutputStream output) throws IOException {
		try (ObjectOutputStream objectOutput = new ObjectOutputStream(output)) {
			objectOutput.writeObject(key);
		}
	}

	/**
	 * Read key from stream.
	 * 
	 * @param input
	 * @return
	 * @throws IOException
	 */
	public default Key readKeyFromStream(InputStream input) throws IOException {
		try (ObjectInputStream objectInput = new ObjectInputStream(input)) {
			return (Key) objectInput.readObject();
		} catch (ClassNotFoundException e) {
			throw new IOException("Class of a serialized object cannot be found.", e);
		}
	}

	/**
	 * Write key to file.
	 * 
	 * @param key
	 * @param file
	 * @throws IOException
	 */
	public default void writeKeyToFile(Key key, File file) throws IOException {
		writeKeyToStream(key, new FileOutputStream(file));
	}

	/**
	 * Read key from file.
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public default Key readKeyFromFile(File file) throws IOException {
		return readKeyFromStream(new FileInputStream(file));
	}

}
